package whendone

/** 
  Filtering mechanisms for filters containing '/', e.g. root/project/sub/
  This needs probably heavy refactoring and could be made much smaller, and general function.
  @author Henrik Huttunen
*/
object PathFiltering{
  import Helpers._
  
  /** Parse next path part from filter: returns (next filter, rest)   
      "/" is included for both filters, like duu/foo -> (duu/, /foo) */
  private def getFilter(filter: String): (String, String) = {
    val index = filter.indexOf("/")
    if(index < 0) (filter, "")
    else (filter.substring(0, index+1), filter.substring(index+1, filter.size)) 
  }
  /** Parses next filter from right to left. */
  private def getLeftFilter(filter: String): (String, String) = {
    val leftFil = getFilter(filter.reverse)
    (leftFil._1 reverse, leftFil._2 reverse)    
  }
  /** Matches 'left' filter processing it from right to left recursively. */
  private def partRecMatchLeft(part: Project, left: String): Boolean = {   
    val leftFilter = getLeftFilter(left)
    (left.isEmpty || leftFilter._1.isEmpty) ||
      (part.parent match {
        case None => leftFilter._2.isEmpty || leftFilter._2.toString == "/"
        case Some(parent) =>
          (if(leftFilter._1.startsWith("/"))
            parent.name.toString == leftFilter._1.substring(1, leftFilter._1.size).toString
          else
            endsWith(parent.name, leftFilter._1)
          ) && partRecMatchLeft(parent, leftFilter._2)
      })
  }
  /** Matches 'right' filter processing it from left to right recursively. */
  private def partRecMatchRight(part: Project, right: String): Boolean = {
    val rightFilter = getFilter(right)
    if(right.isEmpty || rightFilter._1.isEmpty) true
    else if(rightFilter._1.reverse.startsWith("/")){
      part.projects.find(_.name == rightFilter._1.substring(0, rightFilter._1.size-1)) match {
        case None => false
        case Some(child) => partRecMatchRight(child, rightFilter._2)
      }
    }else{
      part.projects.exists(_.name.startsWith(rightFilter._1))
    }
  }
  /** Matches filters with two or more '/'s */
  def pathMatch(part: Project, filter: String): Boolean = {
/*
    def allOfTheNameMatches(startIndex: Int): List[(String, String, String)] = {
      val findable = "/" + part.name + "/"
      val index = filter.indexOf(findable, startIndex)
      if(index < 0) Nil 
      else{
        val left = slice(filter, 0, index-1) 
        val cur = slice(filter, index, index+findable.size-1) 
        val right = slice(filter, index+findable.size, filter.size-1)
        println((left, cur, right))
        (left, cur, right) :: allOfTheNameMatches(index+1)
      }
    }
*/
    /** Creates starting points for part giving configuration of (left, match, right) 
        e.g. first/findable/something/yeah creates List(first, /findable/, something/yeah/) */
    def allOfTheNameMatches(startIndex: Int, allowedIndex: List[Int], prefix: String, postfix: String): List[(String, String, String)] = {
      val findable = prefix + part.name + postfix
      val index = filter.indexOf(findable, startIndex)
      if(index < 0 || !allowedIndex.contains(index)) Nil 
      else{
        val left = slice(filter, 0, index-1) 
        val cur = slice(filter, index, index+findable.size-1) 
        val right = slice(filter, index+findable.size, filter.size-1)
        (left, cur, right) :: allOfTheNameMatches(index+1, allowedIndex, prefix, postfix)
      }
    }
		/** Whether part matches filter starting from left and going right.
        filter: boo/something
        name: aaboo 
    */
    def fromLeft2Right = {
      val index = filter.indexOf("/")
      index > 0 &&
        endsWith(part.name, slice(filter, 0, index-1)) &&
          partRecMatchRight(part, slice(filter, index+1, filter.size-1)) 
    }
    /** Whether part matches filter starting from right and going left.
        something/boo
                  booyay
    */ 
    def fromRight2Left = {
      val index = filter.lastIndexOf("/")
      index >= 0 && index < filter.size - 1
        part.name.startsWith(slice(filter, index+1, filter.size-1)) &&
          partRecMatchLeft(part, slice(filter, 0, index - 1))
    }
//    val matches = allOfTheNameMatches(0)
    val matches = allOfTheNameMatches(0, (0 to filter.size).toList, "/", "/") ::: allOfTheNameMatches(0, List(0), "", "/") ::: allOfTheNameMatches(0, List(filter.size-1), "/", "")
    fromLeft2Right || fromRight2Left || matches.exists(aMatch => partRecMatchLeft(part, aMatch._1) & partRecMatchRight(part, aMatch._3)) 
  }
  /** Matches /name or name/ or /name/ */
  def singlePartMatch(part: Project, filter: String): Boolean = {
    //filters fo = filter.split("/").filter(part.contains _)
    if(filter.startsWith("/") && filter.reverse.startsWith("/"))
      part.name == filter.substring(1, filter.size - 1)
    else {
      (filter.startsWith("/") && part.name.startsWith(filter.substring(1))) ||
      (filter.reverse.startsWith("/") && part.name.reverse.startsWith(filter.reverse.substring(1)))  
    }
  }
  /** Matches firstpart/secondpart */
  def twoPartsMatch(part: Project, filter: String) = {   
    val index = filter.indexOf("/")    
    val left = slice(filter, 0, index-1)
    val right = slice(filter, index+1, filter.size)
    (endsWith(part.name, left) && part.projects.exists(_.name.startsWith(right)) ||
    part.name.startsWith(right) && (part.parent match {
      case None => false
      case Some(parent) => endsWith(parent.name, left)
    }))
  }
}